package org.tamal.servlet;

import java.io.IOException;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Properties;
import java.util.logging.Logger;

import javax.mail.Address;
import javax.mail.BodyPart;
import javax.mail.Message;
import javax.mail.Transport;
import javax.mail.Message.RecipientType;
import javax.mail.MessagingException;
import javax.mail.Multipart;
import javax.mail.Session;
import javax.mail.internet.MimeMessage;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import com.google.appengine.api.datastore.DatastoreService;
import com.google.appengine.api.datastore.DatastoreServiceFactory;
import com.google.appengine.api.datastore.Entity;
import com.google.appengine.api.datastore.Text;

/**
 * Email Servlet will be invoked for each incoming mail.
 * @author Tamal Kanti Nath
 */
public final class EmailServlet extends HttpServlet {

    private static final long serialVersionUID = 3405607329257695238L;
    private final Logger log = Logger.getLogger(getClass().getName());

    @Override
    public void doPost(HttpServletRequest req, HttpServletResponse res)
            throws IOException {
        Properties props = new Properties();
        Session session = Session.getDefaultInstance(props, null);
        try {
            MimeMessage msg = new MimeMessage(session, req.getInputStream());
            log.info("Received a mail from: " + msg.getFrom()[0]
                    + " with subject: " + msg.getSubject());
            saveMessage(msg, req.getRequestURI().substring(10));
            Message reply = msg.reply(true);
            reply.setText("Message received.");
            Transport.send(reply);
        } catch (MessagingException e) {
            log.throwing(getClass().getName(), "doPost", e);
        }
    }

    private static void saveMessage(MimeMessage msg, String recipant)
            throws MessagingException, IOException {
        Entity entity = new Entity("email", recipant + "-" + msg.getMessageID());
        entity.setProperty("sentDate", msg.getSentDate());
        entity.setProperty("receivedDate", new Date());
        entity.setProperty("subject", msg.getSubject());
        entity.setProperty("contentType", msg.getContentType());
        addEmails(entity, msg);
        if (msg.isMimeType("multipart/alternative")) {
            Multipart mp = (Multipart) msg.getContent();
            for (int i = 0; i < mp.getCount(); ++i) {
                BodyPart bp = mp.getBodyPart(i);
                if (bp.isMimeType("text/plain")) {
                    Text text = new Text(bp.getContent().toString());
                    entity.setProperty("body", text);
                }
            }
        }
        if (msg.isMimeType("text/plain")) {
            Text text = new Text(msg.getContent().toString());
            entity.setProperty("body", text);
        }
        DatastoreService ds = DatastoreServiceFactory.getDatastoreService();
        ds.put(entity);
    }

    private static void addEmails(Entity entity, MimeMessage msg)
            throws MessagingException {
        if (msg.getSender() != null) {
            entity.setProperty("sender", msg.getSender().toString());
        }
        if (msg.getFrom() != null) {
            entity.setProperty("from", getEmails(msg.getFrom()));
        }
        if (msg.getReplyTo() != null) {
            entity.setProperty("replyTo", getEmails(msg.getReplyTo()));
        }
        if (msg.getRecipients(RecipientType.TO) != null) {
            entity.setProperty("to",
                    getEmails(msg.getRecipients(RecipientType.TO)));
        }
        if (msg.getRecipients(RecipientType.CC) != null) {
            entity.setProperty("cc",
                    getEmails(msg.getRecipients(RecipientType.CC)));
        }
        if (msg.getRecipients(RecipientType.BCC) != null) {
            entity.setProperty("bcc",
                    getEmails(msg.getRecipients(RecipientType.BCC)));
        }
        if (msg.getRecipients(MimeMessage.RecipientType.NEWSGROUPS) != null) {
            entity.setProperty("newsgroups", getEmails(msg.getRecipients(
                    MimeMessage.RecipientType.NEWSGROUPS)));
        }
    }

    private static List<String> getEmails(Address[] from) {
        List<String> emails = new ArrayList<>();
        for (Address address : from) {
            emails.add(address.toString());
        }
        return emails;
    }
}
